/*
* Copyright (c) 2012 Kyle Hayward
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

//Merge VPLs into a structured grid

struct VPL
{
	float4 pos;
	float4 color;
};

struct Box
{
	float3 min;
	float3 max;
};

#define NUM_THREADS 16

// Declare the input and output resources
RWStructuredBuffer<VPL> VPLs	: register( u0 );

StructuredBuffer<VPL>	Lights	: register( t0 );
StructuredBuffer<Box>   Voxels	: register( t1 );

// Declare enough shared memory for the padded group size
groupshared VPL loadedVPLs[ NUM_THREADS ];


bool BoxContains( Box box, float3 p )
{
	return  p.x >= box.min.x && p.x <= box.max.x &&
			p.y >= box.min.y && p.y <= box.max.y &&
			p.z >= box.min.z && p.z <= box.max.z;
}

float3 BoxCenter( Box box )
{
	return ( box.min + box.max ) * 0.5f;
}

[numthreads( NUM_THREADS, 1, 1)]
void CSMain( uint3 DispatchThreadID : SV_DispatchThreadID,
			 uint3 GroupID : SV_GroupID, 
			 uint3 GroupThreadID : SV_GroupThreadID,
			 uint GroupIndex : SV_GroupIndex )
{
	int voxelIndex = GroupID.x * NUM_THREADS + GroupThreadID.x;

	loadedVPLs[ GroupIndex ] = VPLs[ voxelIndex ];

	Box box = Voxels[ voxelIndex ];

	// Synchronize all threads before moving on to ensure everyone has loaded their state
	// into the group shared memory.
	GroupMemoryBarrierWithGroupSync();

	float3 color = 0;

	uint num, stride;
	Lights.GetDimensions( num, stride );
	for( int i = 0; i < num; i++ )
	{
		VPL vpl = Lights[ i ];

		if( BoxContains( box, vpl.pos.xyz ) )
		{
			color += vpl.color.xyz;
		}
	}

	loadedVPLs[ GroupIndex ].color = float4( color, 1.0f );
	loadedVPLs[ GroupIndex ].pos = float4( BoxCenter( box ), 1.0f );

	// Synchronize all threads before moving on
	GroupMemoryBarrierWithGroupSync();

	VPLs[ voxelIndex ] = loadedVPLs[ GroupIndex ];
}